// SPDX-License-Identifier: GPL-2.0
/*
 * Copyright (c) Huawei Technologies Co., Ltd. 2020. All rights reserved.
 * Generated on: 2020/2/6
 * Function description: adaption related to the PCIe main chip
 */
#include <linux/string.h>
#include "include/mach/pcie_reset.h"
#include "include/mach/pcie_core.h"

extern struct pcie_reg_base_addr *g_pcie_reg_base_addr;

#if KER_F_DESC("internal function")

struct pcie_reg_mask_table {
	uint32_t pcie_acp_reg_addr;
	uint32_t pcie_acp_mask_bit;
};

struct pcie_acp_reg_map {
	uint32_t soc_chip_id;
	struct pcie_reg_mask_table mask_table[PCIE_INDEX_MAX];
};

int32_t set_pcie0_votage_swing(struct pcie_board_ini_attr *pcie_board_cfg)
{
	int32_t ret = 0;
	/* if configed DFX feature exists, take that preferentially */
	if (pcie_board_cfg->dfx_pcie_voltage_amp != PCIE_INVALID_INT32) {
		uint32_t reg_val = 0;
		(void)read_reg_iomap_value(
			g_pcie_reg_base_addr[PCIE_INDEX_0].dbi_base_addr + PCIE_COMBOPHY12_ADDR,
			&reg_val
		);
		ret = write_reg_iomap_value(
			g_pcie_reg_base_addr[PCIE_INDEX_0].dbi_base_addr + PCIE_COMBOPHY12_ADDR,
			pcie_board_cfg->dfx_pcie_voltage_amp
		);
		udelay(PCIE_DELAY_10);
		pr_info("<PCIE0 DFX> voltage register 0x%08x change to 0x%08x\n",
			reg_val, pcie_board_cfg->dfx_pcie_voltage_amp);
		return ret;
	}

	if (pcie_board_cfg->chan_attr[PCIE_INDEX_0].pcie_voltage_swing != PCIE_INVALID_INT32) {
		/* set PCIE0 swing */
		ret = clear_reg_iomap_mask(
			g_pcie_reg_base_addr[PCIE_INDEX_0].dbi_base_addr + PCIE_COMBOPHY12_ADDR,
			pcie_board_cfg->chan_attr[PCIE_INDEX_0].pcie_voltage_swing
		);
		udelay(PCIE_DELAY_10);
	}
	return ret;
}

int32_t set_pcie1_votage_swing(struct pcie_board_ini_attr *pcie_board_cfg)
{
	int32_t ret = 0;
	/* if configed DFX feature exists, take that preferentially */
	if (pcie_board_cfg->dfx_pcie_voltage_amp != PCIE_INVALID_INT32) {
		uint32_t reg_val = 0;
		(void)read_reg_iomap_value(
			g_pcie_reg_base_addr[PCIE_INDEX_1].dbi_base_addr + PCIE_COMBOPHY12_ADDR,
			&reg_val
		);
		ret = write_reg_iomap_value(
			g_pcie_reg_base_addr[PCIE_INDEX_1].dbi_base_addr + PCIE_COMBOPHY12_ADDR,
			pcie_board_cfg->dfx_pcie_voltage_amp
		);
		udelay(PCIE_DELAY_10);
		pr_info("<PCIE1 DFX> voltage register 0x%08x change to 0x%08x\n",
			reg_val, pcie_board_cfg->dfx_pcie_voltage_amp);
		return ret;
	}

	if (pcie_board_cfg->chan_attr[PCIE_INDEX_1].pcie_voltage_swing != PCIE_INVALID_INT32) {
		/* set PCIE1 swing */
		ret = clear_reg_iomap_mask(
			g_pcie_reg_base_addr[PCIE_INDEX_1].dbi_base_addr + PCIE_COMBOPHY12_ADDR,
			pcie_board_cfg->chan_attr[PCIE_INDEX_1].pcie_voltage_swing
		);
		udelay(PCIE_DELAY_10);
	}
	return ret;
}

int32_t set_pcie2_votage_swing(struct pcie_board_ini_attr *pcie_board_cfg)
{
	int32_t ret = 0;
	/* if configed DFX feature exists, take that preferentially */
	if (pcie_board_cfg->dfx_pcie_voltage_amp != PCIE_INVALID_INT32) {
		uint32_t reg_val = 0;
		(void)read_reg_iomap_value(
			g_pcie_reg_base_addr[PCIE_INDEX_2].dbi_base_addr + PCIE_COMBOPHY12_ADDR,
			&reg_val
		);
		ret = write_reg_iomap_value(
			g_pcie_reg_base_addr[PCIE_INDEX_2].dbi_base_addr + PCIE_COMBOPHY12_ADDR,
			pcie_board_cfg->dfx_pcie_voltage_amp
		);
		udelay(PCIE_DELAY_10);
		pr_info("<PCIE1 DFX> voltage register 0x%08x change to 0x%08x\n",
			reg_val, pcie_board_cfg->dfx_pcie_voltage_amp);
		return ret;
	}

	if (pcie_board_cfg->chan_attr[PCIE_INDEX_2].pcie_voltage_swing != PCIE_INVALID_INT32) {
		/* set PCIE2 swing */
		ret = clear_reg_iomap_mask(
			g_pcie_reg_base_addr[PCIE_INDEX_2].dbi_base_addr + PCIE_COMBOPHY12_ADDR,
			pcie_board_cfg->chan_attr[PCIE_INDEX_2].pcie_voltage_swing
		);
		udelay(PCIE_DELAY_10);
	}
	return ret;
}

void pcie_get_mxl_gpio_cfg(struct pcie_board_ini_attr *board_attr,
	struct wifi_mxl_cfg *wifi_gpio, bool *had_mxl_wifi)
{
	/* get mxl gpio */
	*had_mxl_wifi = false;
	if (pcie_is_wifi_mxl_chip(PCIE_INDEX_0) || pcie_is_wifi_mxl_chip(PCIE_INDEX_1)) {
		*had_mxl_wifi = true;
		pcie_get_mxl_board_attr(wifi_gpio);
	}
}

void pcie_undo_reset_mxl_chip(struct pcie_board_ini_attr *board_attr)
{
	int32_t ret;
	struct wifi_mxl_cfg wifi_ctl_gpio;
	bool had_mxl_wifi = false;

	pcie_get_mxl_gpio_cfg(board_attr, &wifi_ctl_gpio, &had_mxl_wifi);
	if (!had_mxl_wifi)
		return;

	ret = set_gpio_dir_output(wifi_ctl_gpio.ctl_0v9_gpio);

	ret |= set_gpio_dir_output(wifi_ctl_gpio.wifi_reset_gpio);
	ret |= set_gpio_output_value(wifi_ctl_gpio.wifi_reset_gpio, GPIO_IO_LOW);
	mdelay(PCIE_DELAY_10);

	ret |= set_gpio_output_value(wifi_ctl_gpio.ctl_0v9_gpio, GPIO_IO_HIGH);
	mdelay(PCIE_DELAY_150);
	ret |= set_gpio_output_value(wifi_ctl_gpio.wifi_reset_gpio, GPIO_IO_HIGH);
	if (ret != 0)
		pr_info("undo mxl reset fail!\n");
}

void pcie_undo_reset_cel_chip(uint32_t wifi0_reset_gpio, uint32_t wifi1_reset_gpio)
{
	(void)set_gpio_dir_output(wifi0_reset_gpio);
	(void)set_gpio_dir_output(wifi1_reset_gpio);
	(void)set_gpio_output_value(wifi0_reset_gpio, GPIO_IO_HIGH);
	(void)set_gpio_output_value(wifi1_reset_gpio, GPIO_IO_HIGH);
	mdelay(PCIE_DELAY_10);

	(void)set_gpio_dir_output(wifi0_reset_gpio);
	(void)set_gpio_dir_output(wifi1_reset_gpio);
	(void)set_gpio_output_value(wifi0_reset_gpio, GPIO_IO_LOW);
	(void)set_gpio_output_value(wifi1_reset_gpio, GPIO_IO_LOW);

	mdelay(PCIE_DELAY_150);
	(void)set_gpio_dir_output(wifi0_reset_gpio);
	(void)set_gpio_dir_output(wifi1_reset_gpio);
	(void)set_gpio_output_value(wifi0_reset_gpio, GPIO_IO_HIGH);
	(void)set_gpio_output_value(wifi1_reset_gpio, GPIO_IO_HIGH);
}

void pcie_unreset_cel_chip(struct pcie_board_ini_attr *board_attr)
{
	uint32_t wifi1_reset_gpio;
	bool had_cel_wifi;
	uint32_t wifi0_reset_gpio = PCIE_INVALID_INT8;

	had_cel_wifi = false;
	if (pcie_is_wifi_cel_chip(PCIE_INDEX_0)) {
		wifi0_reset_gpio = board_attr->chan_attr[PCIE_INDEX_0].wifi_reset_gpio;
		had_cel_wifi = true;
	}

	wifi1_reset_gpio = PCIE_INVALID_INT8;
	if (pcie_is_wifi_cel_chip(PCIE_INDEX_1)) {
		wifi1_reset_gpio = board_attr->chan_attr[PCIE_INDEX_1].wifi_reset_gpio;
		had_cel_wifi = true;
	}

	if (had_cel_wifi)
		pcie_undo_reset_cel_chip(wifi0_reset_gpio, wifi1_reset_gpio);
}

void pcie_get_1152_gpio_cfg(struct pcie_board_ini_attr *board_attr,
	struct wifi_hi1152_cfg *wifi_gpio, bool *had_1152wifi)
{
	*had_1152wifi = false;
	if (pcie_is_wifi1152_chip(PCIE_INDEX_0) || pcie_is_wifi1152_chip(PCIE_INDEX_1)) {
		*had_1152wifi = true;
		pcie_get_1152_board_attr(wifi_gpio);
	}
}

void pcie_undo_reset_hi1152_chip(struct pcie_board_ini_attr *board_attr)
{
	int32_t ret;
	/* get 1152 gpio */
	struct wifi_hi1152_cfg wifi_ctl_gpio;
	bool had_1152wifi = false;

	pcie_get_1152_gpio_cfg(board_attr, &wifi_ctl_gpio, &had_1152wifi);
	if (!had_1152wifi)
		return;

	/* set gpio output */
	ret = set_gpio_dir_output(wifi_ctl_gpio.pcie_rst_gpio);

	ret |= set_gpio_dir_output(wifi_ctl_gpio.wl_en_gpio);
	ret |= set_gpio_dir_output(wifi_ctl_gpio.pmu_pwren_gpio);
	ret |= set_gpio_dir_output(wifi_ctl_gpio.ctl_0v9_gpio);

	/* reset and de-reset pcie */
	ret |= set_gpio_output_value(wifi_ctl_gpio.pcie_rst_gpio, GPIO_IO_LOW);
	/* set drv ability, at most 4mA, prevent excessively large external
	 * capacitors from causing slow reset
	 */
	/* 0x149400EC bit[2:4] = 0 */
	ret |= set_gpio_drv_ability(wifi_ctl_gpio.pcie_rst_gpio, PCIE_GPIO_MAX_ABILITY);
	mdelay(PCIE_DELAY_10);
	ret |= set_gpio_output_value(wifi_ctl_gpio.pcie_rst_gpio, GPIO_IO_HIGH);

	/* reset wifi gpio directly select function, set as output and to be low */
	ret |= set_gpio_output_value(wifi_ctl_gpio.pmu_pwren_gpio, GPIO_IO_LOW);
	ret |= set_gpio_output_value(wifi_ctl_gpio.wl_en_gpio, GPIO_IO_LOW);
	ret |= set_gpio_output_value(wifi_ctl_gpio.ctl_0v9_gpio, GPIO_IO_LOW);
	mdelay(PCIE_DELAY_100);

	/* pull up PMU_POWER WL_EN */
	ret |= set_gpio_output_value(wifi_ctl_gpio.pmu_pwren_gpio, GPIO_IO_HIGH);
	ret |= set_gpio_output_value(wifi_ctl_gpio.wl_en_gpio, GPIO_IO_HIGH);
	mdelay(PCIE_DELAY_100);

	/* pull up POWER */
	ret |= set_gpio_output_value(wifi_ctl_gpio.ctl_0v9_gpio, GPIO_IO_HIGH);
	mdelay(PCIE_DELAY_100);
	if (ret != 0)
		pr_info("undo 1152 reset fail!\n");
}

void pcie_get_dy1153_gpio_cfg(struct pcie_board_ini_attr *board_attr,
	struct wifi_dy1153_cfg *wifi_ctrl_gpio, bool *had_1153wifi)
{
	struct wifi_dy1153_cfg wifi_gpio = {0};

	*had_1153wifi = false;
	(void)memset(wifi_ctrl_gpio, PCIE_INVALID_INT8, sizeof(*wifi_ctrl_gpio));

	pcie_get_dy1153_board_attr(&wifi_gpio);
	if (pcie_is_wifi1153_chip(PCIE_INDEX_0))
		GET_1153_CFG(0);

	if (pcie_is_wifi1153_chip(PCIE_INDEX_1))
		GET_1153_CFG(1);
	wifi_ctrl_gpio->wifi_3v3_power_gpio = wifi_gpio.wifi_3v3_power_gpio;
}

void pcie_undo_reset_dy1153_chip(struct pcie_board_ini_attr *board_attr)
{
	int32_t ret;
	struct wifi_dy1153_cfg wifi_ctl_gpio;
	bool had_1153wifi = false;

	pcie_get_dy1153_gpio_cfg(board_attr, &wifi_ctl_gpio, &had_1153wifi);
	if (!had_1153wifi)
		return;

	if (wifi_ctl_gpio.wifi_3v3_power_gpio != 0xFF) {
		set_gpio_dir_output(wifi_ctl_gpio.wifi_3v3_power_gpio);
		set_gpio_output_value(wifi_ctl_gpio.wifi_3v3_power_gpio, GPIO_IO_HIGH);
	}

	/* set gpio output */
	ret = set_gpio_dir_output(wifi_ctl_gpio.wifi0_power_gpio);

	ret |= set_gpio_dir_output(wifi_ctl_gpio.wifi1_power_gpio);
	ret |= set_gpio_dir_output(wifi_ctl_gpio.ext_rf0_power_gpio);
	ret |= set_gpio_dir_output(wifi_ctl_gpio.ext_rf1_power_gpio);

	/* power off wifi chip and reset pcie */
	WIFI_CTL_GPIO_OUTPUT(ret, wifi, LOW, 50);

	/* power off ex rf and power on again */
	WIFI_CTL_GPIO_OUTPUT(ret, ext_rf, LOW, 10);
	WIFI_CTL_GPIO_OUTPUT(ret, ext_rf, HIGH, 50);

	/* power on wifi chip, reset process completed to prepare for subsequent link establish */
	WIFI_CTL_GPIO_OUTPUT(ret, wifi, HIGH, 100);

	if (ret != 0)
		pr_info("DY1153 de-reset fail!\n");
}

/*
 * to solve th problem of probability that connection failed of pcie on 1153,
 * de-reset wifi cip before de-reset pcie
 */
void pcie_preprocess_dy1153_chip(struct pcie_board_ini_attr *board_attr)
{
	int32_t ret;
	struct wifi_dy1153_cfg wifi_ctl_gpio;
	bool had_1153wifi = false;

	pcie_get_dy1153_gpio_cfg(board_attr, &wifi_ctl_gpio, &had_1153wifi);
	if (!had_1153wifi)
		return;

	/* set gpio output */
	ret = set_gpio_dir_output(wifi_ctl_gpio.wifi0_power_gpio);

	ret |= set_gpio_dir_output(wifi_ctl_gpio.wifi1_power_gpio);
	ret |= set_gpio_dir_output(wifi_ctl_gpio.ext_rf0_power_gpio);
	ret |= set_gpio_dir_output(wifi_ctl_gpio.ext_rf1_power_gpio);

	/* power on ex RF */
	WIFI_CTL_GPIO_OUTPUT(ret, ext_rf, HIGH, 50);

	/* power on wifi chip */
	WIFI_CTL_GPIO_OUTPUT(ret, wifi, HIGH, 100);

	/* power off wifi chip */
	WIFI_CTL_GPIO_OUTPUT(ret, wifi, LOW, 50);

	/* power off ex RF */
	WIFI_CTL_GPIO_OUTPUT(ret, ext_rf, LOW, 10);

	if (ret != 0)
		pr_info("DY1153 preprocess fail!\n");
}

/*
 * note: wifi enable gpio os active high, enable must be before
 * pcie gpio reset, and interval as least 150ms
 */
void pcie_undo_reset_qca_chip(uint32_t gpio_num)
{
	/* set gpio output */
	int32_t ret = set_gpio_dir_output(gpio_num);

	mdelay(PCIE_DELAY_10);

	/* reset/de-reset wifi gpio */
	ret |= set_gpio_output_value(gpio_num, GPIO_IO_LOW);
	msleep(PCIE_DELAY_200);  /* hardware delay require 100ms, margin is 200ms */

	ret |= set_gpio_output_value(gpio_num, GPIO_IO_HIGH);
	msleep(PCIE_DELAY_150);
	if (ret != 0)
		pr_info("enable qca gpio fail!\n");
}

void pcie_proc_qca_wifi_unreset(struct pcie_board_ini_attr *pcie_board_cfg)
{
	WIFI_QCA_DE_RESET(PCIE_INDEX_0);
	WIFI_QCA_DE_RESET(PCIE_INDEX_1);
	WIFI_QCA_DE_RESET(PCIE_INDEX_2);
}

/*
 * note: qualcomm wifi reset gpio reset, and de-reset after 640ms,
 * more 60ms, deset pcie reset(only for HG8245X6-8Ne)
 */
void pcie_set_qca_wifi_reset(uint32_t gpio_num)
{
	/* set gpio output */
	int32_t ret = set_gpio_dir_output(gpio_num);

	mdelay(PCIE_DELAY_10);

	/* wifi reset, default low, set high first */
	ret |= set_gpio_output_value(gpio_num, GPIO_IO_HIGH);
	mdelay(PCIE_DELAY_10);

	/* wifi reset reset 640ms */
	ret |= set_gpio_output_value(gpio_num, GPIO_IO_LOW);
	msleep(PCIE_DELAY_640);

	ret |= set_gpio_output_value(gpio_num, GPIO_IO_HIGH);
	msleep(PCIE_DELAY_40);
	if (ret != 0)
		pr_info("set qca wifi reset fail!\n");
}

void pcie_set_chan_acp(uint32_t acp_enable, uint32_t pcie_index)
{
	uint32_t chip_id;
	uint32_t i;
	struct pcie_acp_reg_map acp_reg_map[] = {
		{ HW_CHIP_ID_5117P_E,
			{{ PCIE_ACP_EN, PCIE_BIT_25 }, { PCIE_ACP_EN, PCIE_BIT_26 }, { 0, 0 }}},
		{ HAL_CHIP_ID_5117PV5,
			{{ PCIE_ACP_EN, PCIE_BIT_25 }, { PCIE_ACP_EN, PCIE_BIT_26 }, { 0, 0 }}},
		{ HW_CHIP_ID_5117V_E,
			{{ PCIE_ACP_EN, PCIE_BIT_25 }, { PCIE_ACP_EN, PCIE_BIT_26 }, { 0, 0 }}},
		{ HW_CHIP_ID_5182H_E,
			{{ PCIE_ACP_EN, PCIE_BIT_25 }, { PCIE_ACP_EN, PCIE_BIT_26 }, { 0, 0 }}},
		{ HAL_CHIP_ID_5182HV5,
			{{ PCIE_ACP_EN, PCIE_BIT_25 }, { PCIE_ACP_EN, PCIE_BIT_26 }, { 0, 0 }}},
		{ HAL_CHIP_ID_5182T,
			{{ PCIE_ACP_EN, PCIE_BIT_25 },
			 { PCIE_ACP_EN, PCIE_BIT_26 },
			 { PCIE_ACP_EN, PCIE_BIT_29 }}},
		{ HAL_CHIP_ID_1156H,
			{{ PCIE_ACP_EN_1156, PCIE_BIT_2 }, { 0, 0 }, { 0, 0 }}},
		{ HAL_CHIP_ID_1155H,
			{{ PCIE_ACP_EN_1156, PCIE_BIT_2 }, { 0, 0 }, { 0, 0 }}},
	};

	if ((pcie_index >= PCIE_INDEX_MAX) ||
	    (acp_enable > PCIE_ACP_ENABLE) ||
	    (acp_enable < PCIE_ACP_CLOSE))
		return;

	chip_id = pcie_get_chip_id();
	for (i = 0; i < ARRAY_SIZE(acp_reg_map); i++) {
		struct pcie_reg_mask_table *mask_table;

		if (chip_id != acp_reg_map[i].soc_chip_id)
			continue;

		/* target chip, ACP is enabled or disabled by channel */
		pr_info("set pcie%u ACP %s\n",
			pcie_index, acp_enable == PCIE_ACP_ENABLE ? "enable" : "disable");
		mask_table = &(acp_reg_map[i].mask_table[pcie_index]);

		if (mask_table->pcie_acp_reg_addr == 0)
			continue;
		pr_info("set pcie%u ACP %s\n",
			pcie_index, acp_enable == PCIE_ACP_ENABLE ? "enable" : "disable");
		if (acp_enable == PCIE_ACP_CLOSE)
			set_reg_iomap_bit(mask_table->pcie_acp_reg_addr,
				mask_table->pcie_acp_mask_bit);
		else
			clear_reg_iomap_bit(mask_table->pcie_acp_reg_addr,
				mask_table->pcie_acp_mask_bit);
	}
}
EXPORT_SYMBOL(pcie_set_chan_acp);

/*
 * note: SD5182H & QCN wifi using offloading, acp closed by default
 */
void pcie_config_channel_acp(struct pcie_board_ini_attr *board_attr)
{
	uint32_t chip_id = pcie_get_chip_id();
	uint32_t index;

	for (index = 0; index < PCIE_INDEX_MAX; index++) {
		uint32_t acp_enable;

		acp_enable = board_attr->chan_attr[index].pcie_acp_close;
		if (pcie_is_wifi_qca_chip(index) &&
		    ((chip_id == HW_CHIP_ID_5182H_E) || (chip_id == HAL_CHIP_ID_5182HV5))) {
			/* qualcomm wifi & SD5182H close ACP by default */
			acp_enable = PCIE_ACP_CLOSE;
		}
		if (pcie_is_wifi1152_chip(index) &&
		    ((is_sd5117p_series()) || (chip_id == HW_CHIP_ID_5117V_E))) {
			/* 1152 & 17P, 17V all close PCIE and ACP */
			acp_enable = PCIE_ACP_CLOSE;
		}

		if (pcie_aging_loopback_check() != 0) {
			pr_info("pcie loopback enable acp enable\n");
			acp_enable = PCIE_ACP_ENABLE;
			if ((chip_id == HAL_CHIP_ID_1156H) || (chip_id == HAL_CHIP_ID_1155H) ||
				(chip_id == HAL_CHIP_ID_1156E) || (chip_id == HAL_CHIP_ID_2952H))
				acp_enable = PCIE_ACP_CLOSE;
		}

		pcie_set_chan_acp(acp_enable, index);
	}
}

/*
 * config acp cache work mode of pcie channel
 */
void pcie_acp_coherent_set(void)
{
	/* PCIE0 */
	if (pcie_is_wifi1152_chip(PCIE_INDEX_0)) {
		pr_info("pcie0 acp coherent need set\n");
		clear_reg_iomap_bit(SYS_CTL_PCIE_PORT_ADDR, PCIE_BIT_26);
		clear_reg_iomap_bit(SYS_CTL_PCIE_PORT_ADDR, PCIE_BIT_19);
	}

	/* PCIE1 */
	if (pcie_is_wifi1152_chip(PCIE_INDEX_1)) {
		pr_info("pcie1 acp coherent need set\n");
		clear_reg_iomap_bit(SYS_CTL_PCIE_PORT_ADDR, PCIE_BIT_10);
		clear_reg_iomap_bit(SYS_CTL_PCIE_PORT_ADDR, PCIE_BIT_3);
	}
}

static int32_t pcie_undo_reset_5115(struct pcie_board_ini_attr *pcie_board_cfg, bool is_open)
{
	int32_t ret;

	if (!is_open)
		return 0;

	ret = set_reg_iomap_mask(PCIE_MODEL_UNRESET_REG_5115, PCIE_MODEL_UNRESET_5115);
	if (ret != 0)
		pr_info("<%s:%d> iomap operation failed!\n", __FILE__, __LINE__);
	mdelay(PCIE_DELAY_10);

	/* gpio mode and reset done in u-boot, sd5115t need to de-reset pcie and wifi */
	if (pcie_board_cfg->pcie_channel_select & PCIE1_MODE_SEL) {
		/* de-reset pcie1 wifi1 */
		ret = set_gpio_output_value(
			pcie_board_cfg->chan_attr[PCIE_INDEX_1].pcie_reset_gpio, GPIO_IO_HIGH
		);
		ret |= set_gpio_output_value(
			pcie_board_cfg->chan_attr[PCIE_INDEX_1].wifi_reset_gpio, GPIO_IO_HIGH
		);
		if (ret != 0)
			return ret;
	} else if (pcie_board_cfg->pcie_channel_select & PCIE0_MODE_SEL) {
		/* de-reset pcie0 wifi0 */
		ret = set_gpio_output_value(
			pcie_board_cfg->chan_attr[PCIE_INDEX_0].pcie_reset_gpio, GPIO_IO_HIGH
		);
		ret |= set_gpio_output_value(
			pcie_board_cfg->chan_attr[PCIE_INDEX_0].wifi_reset_gpio, GPIO_IO_HIGH
		);
		if (ret != 0)
			return ret;
	}
	mdelay(PCIE_DELAY_100);
	return 0;
}

static int32_t pcie_undo_reset_5116h(struct pcie_board_ini_attr *pcie_board_cfg, bool is_open)
{
	int32_t ret;

	if (!is_open)
		return 0;

	/* gpio mode and reset done in u-boot, de-reset pcie0 */
	ret = set_gpio_output_value(
		pcie_board_cfg->chan_attr[PCIE_INDEX_0].pcie_reset_gpio, GPIO_IO_HIGH
	);
	if (ret != 0)
		return ret;

	/* de-reset pcie controller */
	ret = set_reg_iomap_bit(PCIE_CTRL_RST_REG, PCIE_BIT_18);
	if (ret != 0)
		return ret;

	mdelay(PCIE_DELAY_10);

	/* de-reset wifi chip */
	ret |= set_gpio_output_value(
		pcie_board_cfg->chan_attr[PCIE_INDEX_0].wifi_reset_gpio, GPIO_IO_HIGH
	);
	if (ret != 0)
		return ret;

	mdelay(PCIE_DELAY_100);
	return 0;
}

static int32_t undo_reset_5116t_pcie(struct pcie_board_ini_attr *pcie_board_cfg, uint32_t index)
{
	int32_t ret;

	const static int pcie_para_list[][2] = {
		/* paras for 5116t pcie0 and pcie1 */
		{PCIE_INDEX_0,           PCIE_INDEX_1},
		{PCIE_BIT_27,            PCIE_BIT_28},
		{PCIE_BIT_15,            PCIE_BIT_16},
		{PCIE_CLK_EN_BIT13_MASK, PCIE_CLK_EN_BIT14_MASK},
		{PCIE_BIT_6,             PCIE_BIT_7},
		{PCIE_BIT_8,             PCIE_BIT_9},
		{PCIE_BIT_18,            PCIE_BIT_22}
	};

	if (index >= ARRAY_SIZE(pcie_para_list[0]))
		return -EINVAL;

	/* set output dir */
	ret = set_gpio_dir_output(pcie_board_cfg->chan_attr[GET_PARA(0)].pcie_reset_gpio);
	ret |= set_gpio_dir_output(pcie_board_cfg->chan_attr[GET_PARA(0)].wifi_reset_gpio);
	if (ret != HW_RET_SUCCESS)
		return ret;

	/* set pcie multiplex relation, GPIO59 */
	/* pcie1 iomux */
	ret = clear_reg_iomap_bit(PCIE_IOMUX_GROP1_REG, GET_PARA(1));
	/* pcie1 function select */
	ret |= set_reg_iomap_bit(PCIE_IOMUX_FUN_SELECT_REG, GET_PARA(2));
	if (ret != HW_RET_SUCCESS)
		return ret;

	/* de-reset pcie1 */
	ret = set_gpio_output_value(
		pcie_board_cfg->chan_attr[GET_PARA(0)].pcie_reset_gpio, GPIO_IO_HIGH
	);
	udelay(PCIE_DELAY_500);
	ret |= set_gpio_output_value(
		pcie_board_cfg->chan_attr[GET_PARA(0)].wifi_reset_gpio, GPIO_IO_HIGH
	);
	udelay(PCIE_DELAY_500);
	if (ret != HW_RET_SUCCESS)
		return ret;

	/* enable pcie clock */
	ret = write_reg_iomap_value(PCIE_CLK_EN_REG2, GET_PARA(3));
	/* de-reset pcie APB */
	ret |= set_reg_iomap_bit(PCIE_APB_RST_REG, GET_PARA(4));

	udelay(PCIE_DELAY_10);
	ret |= set_pcie1_votage_swing(pcie_board_cfg);

	udelay(PCIE_DELAY_10);
	ret |= set_reg_iomap_bit(PCIE_APB_RST_REG, GET_PARA(5)); /* de-reset pcie phy */
	udelay(PCIE_DELAY_10);
	ret |= set_reg_iomap_bit(PCIE_CTRL_RST_REG, GET_PARA(6)); /* de-reset pcie controller */
	udelay(PCIE_DELAY_10);

	return ret;
}

static int32_t pcie_undo_reset_5116t(struct pcie_board_ini_attr *pcie_board_cfg, bool is_open)
{
	int32_t ret;

	if (!is_open)
		return 0;

	ret = DE_RESET_PCIE(1, 5116t_pcie, pcie_board_cfg, 1);
	if (ret != HW_RET_SUCCESS)
		return ret;

	ret = DE_RESET_PCIE(0, 5116t_pcie, pcie_board_cfg, 0);
	return ret;
}

static int32_t pcie_undo_reset_1156(struct pcie_board_ini_attr *pcie_board_cfg, bool is_open)
{
	int32_t ret;

	if (!is_open) {
		/* reset module */
		clear_reg_iomap_mask_set_val(PCIE_CTRL_RST_1156_REG, PCIE_CTRL_RST_1156_MSK, 0);
		/* close clk */
		clear_reg_iomap_mask_set_val(PCIE_CTRL_CLK_1156_REG, PCIE_CTRL_CLK_1156_MSK, 0);
		/* close clk */
		clear_reg_iomap_mask_set_val(PCIE_CTRL_CLK_PHY_1156_REG,
			PCIE_CTRL_CLK_PHY_1156_MSK, 0);
		clear_reg_iomap_mask_set_val(PCIE_CTRL_REFCLK_CTRL_REG, PCIE_CTRL_REFCLK_CTRL_MSK,
			PCIE_CTRL_REFCLK_CTRL_MSK);
		clear_reg_iomap_mask_set_val(PCIE_CTRL_UPSPHY_RST_REG, PCIE_CTRL_UPSPHY_RST_MSK, 0);
		return 0;
	}

	/* 1156 only support 1 PCIE */
	if ((pcie_board_cfg->pcie_channel_select & PCIE0_MODE_SEL) == 0)
		return 0;

	/* set output dir */
	ret = set_gpio_dir_output(pcie_board_cfg->chan_attr[PCIE_INDEX_1].pcie_reset_gpio);

	ret |= set_gpio_dir_output(pcie_board_cfg->chan_attr[PCIE_INDEX_1].wifi_reset_gpio);
	if (ret != HW_RET_SUCCESS)
		return ret;

	/* de-reset pcie1, wifi1 */
	ret = set_gpio_output_value(
		pcie_board_cfg->chan_attr[PCIE_INDEX_1].pcie_reset_gpio, GPIO_IO_HIGH
	);
	udelay(PCIE_DELAY_500);
	ret |= set_gpio_output_value(
		pcie_board_cfg->chan_attr[PCIE_INDEX_1].wifi_reset_gpio, GPIO_IO_HIGH
	);
	udelay(PCIE_DELAY_500);
	if (ret != HW_RET_SUCCESS)
		return ret;

	/* reset module */
	ret |= clear_reg_iomap_mask_set_val(PCIE_CTRL_RST_1156_REG, PCIE_CTRL_RST_1156_MSK, 0);
	/* close clk */
	ret |= clear_reg_iomap_mask_set_val(PCIE_CTRL_CLK_1156_REG, PCIE_CTRL_CLK_1156_MSK, 0);
	/* close clk */
	ret |= clear_reg_iomap_mask_set_val(PCIE_CTRL_CLK_PHY_1156_REG,
		PCIE_CTRL_CLK_PHY_1156_MSK, 0);
	if (ret != HW_RET_SUCCESS)
		return ret;

	udelay(PCIE_DELAY_20);

	/* open clk */
	ret |= clear_reg_iomap_mask_set_val(PCIE_CTRL_REFCLK_CTRL_REG,
		PCIE_CTRL_REFCLK_CTRL_MSK, 0);
	ret |= clear_reg_iomap_mask_set_val(PCIE_CTRL_UPSPHY_RST_REG, PCIE_CTRL_UPSPHY_RST_MSK,
		PCIE_CTRL_UPSPHY_RST_MSK);
	ret |= clear_reg_iomap_mask_set_val(PCIE_CTRL_CLK_1156_REG,
		PCIE_CTRL_CLK_1156_MSK, PCIE_CTRL_CLK_1156_MSK);
	ret |= clear_reg_iomap_mask_set_val(PCIE_CTRL_CLK_PHY_1156_REG,
		PCIE_CTRL_CLK_PHY_1156_MSK, PCIE_CTRL_CLK_PHY_1156_MSK);

	udelay(PCIE_DELAY_10);
	ret |= set_pcie1_votage_swing(pcie_board_cfg);

	udelay(PCIE_DELAY_10);
	/* de-reset module */
	ret |= clear_reg_iomap_mask_set_val(PCIE_CTRL_RST_1156_REG,
		PCIE_CTRL_RST_1156_MSK, PCIE_CTRL_RST_1156_MSK);
	udelay(PCIE_DELAY_10);
	if (ret == HW_RET_SUCCESS)
		pcie_config_channel_acp(pcie_board_cfg);
	return ret;
}

static int32_t undo_reset_5118_pcie(uint32_t pcie_id, struct pcie_rst_ctrl_5118 rst_ctrl_bit)
{
	uint32_t val;
	int32_t ret;

	void *__iomem pcie_misc_base = NULL;

	pr_info("pcie 5118 undo reset start %d\n", pcie_id);
	pcie_get_misc_base_virt(pcie_id, &pcie_misc_base);
	pcie_misc_base = pcie_misc_base + PCIE_MEM_LIMIT_OFFSET;

	/* de-reset pcie, wifi reset gpio */
	ret = set_gpio_dir_output(rst_ctrl_bit.pcie_rst_gpio[pcie_id]);

	ret |= set_gpio_dir_output(rst_ctrl_bit.wifi_rst_gpio[pcie_id]);
	ret |= set_gpio_output_value(rst_ctrl_bit.pcie_rst_gpio[pcie_id], GPIO_IO_HIGH);
	ret |= set_gpio_output_value(rst_ctrl_bit.wifi_rst_gpio[pcie_id], GPIO_IO_HIGH);
	udelay(PCIE_DELAY_10);
	if (ret != HW_RET_SUCCESS)
		return ret;

	ret = read_reg_iomap_value(PCIE_PER_CTRL_GATE_5118_REG, &val);
	val |= (1 << rst_ctrl_bit.clk_en_bit[pcie_id]);
	ret |= write_reg_iomap_value(PCIE_CLK_EN_REG2, val);  /* clk enable */
	udelay(PCIE_DELAY_1000);
	ret |= set_reg_iomap_bit(PCIE_APB_RST_REG, rst_ctrl_bit.apb_rst_bit[pcie_id]);
	udelay(PCIE_DELAY_1000);
	set_reg_bit(pcie_misc_base, rst_ctrl_bit.mem_limit_bit[pcie_id]);
	udelay(PCIE_DELAY_10);
	ret |= set_reg_iomap_bit(PCIE_APB_RST_REG, rst_ctrl_bit.phy_rst_bit[pcie_id]);
	udelay(PCIE_DELAY_1000);
	ret |= set_reg_iomap_bit(PCIE_CTRL_RST_REG, rst_ctrl_bit.pcie_rst_bit[pcie_id]);
	udelay(PCIE_DELAY_1000);
	if (ret != HW_RET_SUCCESS)
		return ret;

	pr_info("pcie 5118 undo reset end\n");
	return HW_RET_SUCCESS;
}

static int32_t pcie_undo_reset_5118(struct pcie_board_ini_attr *pcie_board_cfg, bool is_open)
{
	int32_t ret;
	struct pcie_rst_ctrl_5118 rst_ctrl_bit;

	if (!is_open)
		return 0;

	rst_ctrl_bit.pcie_rst_gpio[PCIE_INDEX_0] =
		pcie_board_cfg->chan_attr[PCIE_INDEX_0].pcie_reset_gpio;
	rst_ctrl_bit.pcie_rst_gpio[PCIE_INDEX_1] =
		pcie_board_cfg->chan_attr[PCIE_INDEX_1].pcie_reset_gpio;

	rst_ctrl_bit.wifi_rst_gpio[PCIE_INDEX_0] =
		pcie_board_cfg->chan_attr[PCIE_INDEX_0].wifi_reset_gpio;
	rst_ctrl_bit.wifi_rst_gpio[PCIE_INDEX_1] =
		pcie_board_cfg->chan_attr[PCIE_INDEX_1].wifi_reset_gpio;

	rst_ctrl_bit.mem_limit_bit[PCIE_INDEX_0] = PCIE_BIT_5;
	rst_ctrl_bit.mem_limit_bit[PCIE_INDEX_1] = PCIE_BIT_5;

	rst_ctrl_bit.apb_rst_bit[PCIE_INDEX_0] = PCIE_BIT_6;
	rst_ctrl_bit.apb_rst_bit[PCIE_INDEX_1] = PCIE_BIT_7;

	rst_ctrl_bit.phy_rst_bit[PCIE_INDEX_0] = PCIE_BIT_8;
	rst_ctrl_bit.phy_rst_bit[PCIE_INDEX_1] = PCIE_BIT_9;

	rst_ctrl_bit.clk_en_bit[PCIE_INDEX_0] = PCIE_BIT_13;
	rst_ctrl_bit.clk_en_bit[PCIE_INDEX_1] = PCIE_BIT_14;

	rst_ctrl_bit.pcie_rst_bit[PCIE_INDEX_0] = PCIE_BIT_18;
	rst_ctrl_bit.pcie_rst_bit[PCIE_INDEX_1] = PCIE_BIT_22;

	ret = DE_RESET_PCIE(1, 5118_pcie, PCIE_INDEX_1, rst_ctrl_bit);
	if (ret != HW_RET_SUCCESS)
		return ret;

	ret = DE_RESET_PCIE(0, 5118_pcie, PCIE_INDEX_0, rst_ctrl_bit);
	return ret;
}

static int32_t pcie_undo_reset_5117h(struct pcie_board_ini_attr *pcie_board_cfg, bool is_open)
{
	int32_t ret;

	if (!is_open)
		return 0;

	if (pcie_board_cfg->pcie_channel_select & PCIE0_MODE_SEL) {
		/* pcie0 iomux wifi low power select 0x14900120[31]=1 */
		ret = set_reg_iomap_bit(PCIE_IOMUX_GROP1_5117H_REG, PCIE_BIT_31);
		if (ret != HW_RET_SUCCESS)
			return ret;

		ret = set_gpio_dir_output(pcie_board_cfg->chan_attr[PCIE_INDEX_0].wifi_reset_gpio);
		ret |= set_gpio_output_value(
			pcie_board_cfg->chan_attr[PCIE_INDEX_0].wifi_reset_gpio,
			GPIO_IO_HIGH
		);
		mdelay(PCIE_DELAY_10);
		if (ret != HW_RET_SUCCESS)
			return ret;

		/* PCIE0 enable clk, 0x14880020[13]=1 */
		ret = set_reg_iomap_bit(PCIE_CLK_EN_REG2, PCIE_BIT_13);
		/* PCIE0 APB bus side soft reset,0x14880034[6]=1 */
		ret |= set_reg_iomap_bit(PCIE_APB_RST_REG, PCIE_BIT_6);
		/* PCIE0 PHY soft reset, 0x14880034[8]=1 */
		ret |= set_reg_iomap_bit(PCIE_APB_RST_REG, PCIE_BIT_8);
		/* PCIE0 PCS soft reset, 0x14880034[7]=1 */
		ret |= set_reg_iomap_bit(PCIE_APB_RST_REG, PCIE_BIT_7);
		mdelay(PCIE_DELAY_10);
		/* PCIE module logic reset,5117H 0x1488002c[18]=1 */
		ret |= set_reg_iomap_bit(PCIE_CTRL_RST_REG, PCIE_BIT_18);
	}

	return ret;
}

static int32_t undo_reset_pcie_wifi(struct pcie_board_ini_attr *pcie_board_cfg, uint32_t pcie_index)
{
	uint32_t pcie_reset_gpio;
	uint32_t wifi_reset_gpio;
	int32_t ret;

	if (pcie_index >= PCIE_INDEX_MAX)
		return -EIO;

	pcie_reset_gpio = pcie_board_cfg->chan_attr[pcie_index].pcie_reset_gpio;
	wifi_reset_gpio = pcie_board_cfg->chan_attr[pcie_index].wifi_reset_gpio;

	ret = set_gpio_dir_output(pcie_reset_gpio);
	ret |= set_gpio_dir_output(wifi_reset_gpio);
	ret |= set_gpio_output_value(pcie_reset_gpio, GPIO_IO_HIGH);
	ret |= set_gpio_output_value(wifi_reset_gpio, GPIO_IO_HIGH);
	mdelay(PCIE_DELAY_10);
	return ret;
}

static int32_t undo_reset_5117p_pcie(struct pcie_board_ini_attr *pcie_board_cfg, uint32_t index)
{
	int32_t ret;
	uint32_t qca_wifi_reset_gpio;

	const static int pcie_para_list[][2] = {
		/* paras for 5117p pcie0 and pcie1 */
		{PCIE0_REF_CLK_MASK,     PCIE1_REF_CLK_MASK},
		{PCIE_INDEX_0,           PCIE_INDEX_1},
		{PCIE0_IO_CFG_5117P_REG, PCIE1_IO_CFG_5117P_REG},
		{PCIE_BIT_6,             PCIE_BIT_7},
		{PCIE_BIT_8,             PCIE_BIT_9},
		{PCIE_BIT_30,            PCIE_BIT_31},
		{PCIE_BIT_18,            PCIE_BIT_22}
	};

	if (index >= ARRAY_SIZE(pcie_para_list[0]))
		return -EINVAL;

	/* open wifi ref clk */
	ret = clear_reg_iomap_mask(PCIE_REF_CLK_EN_REG, GET_PARA(0));
	if (ret != HW_RET_SUCCESS)
		return ret;

	/* de-reset */
	ret = undo_reset_pcie_wifi(pcie_board_cfg, GET_PARA(1));
	if (ret != HW_RET_SUCCESS)
		return ret;

	/* qualcomm wifi reset chip reset, after 640ms de-reset, more 60ms, de-reset pcie reset */
	qca_wifi_reset_gpio =
		pcie_board_cfg->qca_wifi_attr[GET_PARA(1)].qca_wifi_reset_gpio;
	if (pcie_is_wifi_qca_chip(GET_PARA(1)) && (qca_wifi_reset_gpio != PCIE_INVALID_INT8)) {
		pcie_set_qca_wifi_reset(qca_wifi_reset_gpio);
		pr_info("qca_wifi%d_reset_gpio = %u\n", index, qca_wifi_reset_gpio);
		mdelay(PCIE_DELAY_10);
	}

	/* PCIE ref clk cfg */
	ret = write_reg_iomap_value(GET_PARA(2), PCIE_DS_REF_CLK_EN);
	if (ret != HW_RET_SUCCESS)
		return ret;

	/* de-reset pcie1 apb, 0x148a0034[7] = 1'b1 */
	ret = set_reg_iomap_bit(PCIE_RST_CTRL_5117P_REG2, GET_PARA(3));
	udelay(PCIE_DELAY_10);
	/* set pcie1 swing based on cfg file */
	if (index == 1)
		ret |= set_pcie1_votage_swing(pcie_board_cfg);
	else
		ret |= set_pcie0_votage_swing(pcie_board_cfg);
	/* de-reset pcie1 phy, 0x148a0034[9] = 1'b1 */
	ret |= set_reg_iomap_bit(PCIE_RST_CTRL_5117P_REG2, GET_PARA(4));
	udelay(PCIE_DELAY_10);
	/* de-reset pcie1 pcs, 0x148a0034[31] = 1'b1 */
	ret |= set_reg_iomap_bit(PCIE_RST_CTRL_5117P_REG2, GET_PARA(5));
	udelay(PCIE_DELAY_10);
	/* de-reset pcie1 ctrl, 0x148a002c[22] = 1'b1 */
	ret |= set_reg_iomap_bit(PCIE_RST_CTRL_5117P_REG0, GET_PARA(6));
	udelay(PCIE_DELAY_10);

	return ret;
}

static int32_t pcie_undo_reset_5117p(struct pcie_board_ini_attr *pcie_board_cfg, bool is_open)
{
	int32_t ret = 0;

	if (!is_open)
		return 0;

	/* wifi chip process */
	pcie_proc_qca_wifi_unreset(pcie_board_cfg);
	pcie_unreset_cel_chip(pcie_board_cfg);
	pcie_preprocess_dy1153_chip(pcie_board_cfg);

	/* PCIE1 init */
	ret = DE_RESET_PCIE(1, 5117p_pcie, pcie_board_cfg, 1);
	if (ret != HW_RET_SUCCESS)
		return ret;

	/* PCIE0 init */
	ret = DE_RESET_PCIE(0, 5117p_pcie, pcie_board_cfg, 0);
	if (ret != HW_RET_SUCCESS)
		return ret;

	pcie_undo_reset_hi1152_chip(pcie_board_cfg);
	pcie_undo_reset_mxl_chip(pcie_board_cfg);
	pcie_undo_reset_dy1153_chip(pcie_board_cfg);

	/* ACP cfg */
	pcie_config_channel_acp(pcie_board_cfg);
	return ret;
}

static int32_t undo_reset_5117v_pcie(struct pcie_board_ini_attr *pcie_board_cfg, uint32_t index)
{
	int32_t ret;

	const static int pcie_para_list[][2] = {
		/* paras for 5117v pcie0 and pcie1 */
		{PCIE0_REF_CLK_MASK,     PCIE1_REF_CLK_MASK},
		{PCIE0_IO_CFG_5117P_REG, PCIE1_IO_CFG_5117P_REG},
		{PCIE_INDEX_0,           PCIE_INDEX_1},
		{PCIE_BIT_6,             PCIE_BIT_7},
		{PCIE_BIT_8,             PCIE_BIT_9},
		{PCIE_BIT_30,            PCIE_BIT_31},
		{PCIE_BIT_18,            PCIE_BIT_22}
	};

	if (index >= ARRAY_SIZE(pcie_para_list[0]))
		return -EINVAL;

	/* enable wifi ref clk */
	ret = clear_reg_iomap_mask(PCIE_REF_CLK_EN_REG, GET_PARA(0));
	if (ret != HW_RET_SUCCESS)
		return ret;

	/* set PCIE ref clk */
	ret = write_reg_iomap_value(GET_PARA(1), PCIE_DS_REF_CLK_EN);
	if (ret != HW_RET_SUCCESS)
		return ret;

	/* de-reset pcie */
	ret = set_gpio_dir_output(
		pcie_board_cfg->chan_attr[GET_PARA(2)].pcie_reset_gpio
	);
	ret |= set_gpio_dir_output(
		pcie_board_cfg->chan_attr[GET_PARA(2)].wifi_reset_gpio
	);
	ret |= set_gpio_output_value(
		pcie_board_cfg->chan_attr[GET_PARA(2)].pcie_reset_gpio, GPIO_IO_HIGH
	);
	if (ret != HW_RET_SUCCESS)
		return ret;

	/* de-reset pcie apb, 0x148a0034[6 or 7] = 1'b1 */
	ret |= set_reg_iomap_bit(PCIE_RST_CTRL_5117V_REG2, GET_PARA(3));
	udelay(PCIE_DELAY_10);
	/* set pcie1 swing based on cfg file */
	if (index == 1)
		ret |= set_pcie1_votage_swing(pcie_board_cfg);
	else
		ret |= set_pcie0_votage_swing(pcie_board_cfg);
	/* de-reset pcie1 phy, 0x148a0034[8 or 9] = 1'b1 */
	ret |= set_reg_iomap_bit(PCIE_RST_CTRL_5117V_REG2, GET_PARA(4));
	udelay(PCIE_DELAY_10);
	/* de-reset pcie1 pcs, 0x148a0034[30 or 31] = 1'b1 */
	ret |= set_reg_iomap_bit(PCIE_RST_CTRL_5117V_REG2, GET_PARA(5));
	udelay(PCIE_DELAY_10);
	/* de-reset pcie1 controller, 0x148a002c[18 or 22] = 1'b1 */
	ret |= set_reg_iomap_bit(PCIE_RST_CTRL_5117V_REG0, GET_PARA(6));
	udelay(PCIE_DELAY_10);
	if (ret != HW_RET_SUCCESS)
		return ret;

	/* de-reset wifi */
	ret = set_gpio_output_value(
		pcie_board_cfg->chan_attr[GET_PARA(2)].wifi_reset_gpio, GPIO_IO_HIGH
	);

	return ret;
}

static int32_t pcie_undo_reset_5117v(struct pcie_board_ini_attr *pcie_board_cfg, bool is_open)
{
	int32_t ret;

	if (!is_open)
		return 0;

	pcie_proc_qca_wifi_unreset(pcie_board_cfg);
	pcie_unreset_cel_chip(pcie_board_cfg);
	pcie_preprocess_dy1153_chip(pcie_board_cfg);

	/*
	* 17v has a new security feature, need to set pcie to security mode. only master
	* TZPC_MST 0x10100008 pcie0_mst_prot_cfg, pcie1_mst_prot_cfg bit[0:1]=0 needed
	*/
	ret = clear_reg_iomap_bit(PCIE_TZPC_MST_REG, PCIE_BIT_0);

	ret |= clear_reg_iomap_bit(PCIE_TZPC_MST_REG, PCIE_BIT_1);
	if (ret != HW_RET_SUCCESS)
		return ret;

	ret = DE_RESET_PCIE(1, 5117v_pcie, pcie_board_cfg, 1);
	if (ret != HW_RET_SUCCESS)
		return ret;

	ret = DE_RESET_PCIE(0, 5117v_pcie, pcie_board_cfg, 0);
	if (ret != HW_RET_SUCCESS)
		return ret;

	pcie_undo_reset_hi1152_chip(pcie_board_cfg);
	pcie_undo_reset_mxl_chip(pcie_board_cfg);
	pcie_undo_reset_dy1153_chip(pcie_board_cfg);

	/* ACP cfg */
	pcie_config_channel_acp(pcie_board_cfg);
	return ret;
}

static int32_t undo_reset_5117l_pcie(struct pcie_board_ini_attr *pcie_board_cfg, uint32_t index)
{
	uint32_t pcie_gpio_ability;
	int32_t ret;
	uint32_t *value = NULL;

	const static int pcie_para_list[][2] = {
		/* paras for 5117l pcie0 and pcie1 */
		{PCIE0_REF_CLK_MASK, PCIE1_REF_CLK_MASK},
		{PCIE_INDEX_0,       PCIE_INDEX_1},
		{PCIE_BIT_13,        PCIE_BIT_15},
		{PCIE_BIT_14,        PCIE_BIT_16},
		{PCIE_BIT_9,         PCIE_BIT_10},
		{0,                  PCIE1_BASE_REG_OFFSET},
		{PCIE_BIT_11,        PCIE_BIT_12},
		{PCIE_BIT_17,        PCIE_BIT_18}
	};

	if (index >= ARRAY_SIZE(pcie_para_list[0]))
		return -EINVAL;

	pcie_gpio_ability = PCIE_GPIO_MAX_ABILITY;
	/* enable wifi ref clk */
	ret = clear_reg_iomap_mask(PCIE_REF_CLK_EN_REG, GET_PARA(0));
	if (ret != HW_RET_SUCCESS)
		return ret;

	/* reset wifi chip, set drv ablity max,
	 * if cfg file configured it, set to configured value
	 */
	ret = set_gpio_dir_output(
		pcie_board_cfg->chan_attr[GET_PARA(1)].wifi_reset_gpio
	);
	if (pcie_board_cfg->chan_attr[GET_PARA(1)].pcie_drv_ability <
		PCIE_GPIO_MAX_ABILITY)
		pcie_gpio_ability =
			pcie_board_cfg->chan_attr[GET_PARA(1)].pcie_drv_ability;

	ret |= clear_reg_iomap_mask((PCIE_PAD_DIO_BASE + (PCIE_GPIO_CTRL_REG_LEN *
		pcie_board_cfg->chan_attr[GET_PARA(1)].wifi_reset_gpio)),
		pcie_gpio_ability);

	ret |= set_gpio_output_value(
		pcie_board_cfg->chan_attr[GET_PARA(1)].wifi_reset_gpio, GPIO_IO_LOW
	);
	if (ret != HW_RET_SUCCESS)
		return ret;

	/* enable PCIE1 controller, enable PCIE pipe clk */
	ret = set_reg_iomap_bit(PCIE_CLK_EN_REG2, GET_PARA(2));
	ret |= set_reg_iomap_bit(PCIE_CLK_EN_REG2, GET_PARA(3));
	mdelay(PCIE_DELAY_100);
	if (ret != HW_RET_SUCCESS)
		return ret;

	/* de-reset pcie1 connected devices */
	ret = set_gpio_output_value(
		pcie_board_cfg->chan_attr[GET_PARA(1)].wifi_reset_gpio, GPIO_IO_HIGH
	);
	if (ret != HW_RET_SUCCESS)
		return ret;

	/* de-reset pcie0 apb, 0x1488002c[10] = 1'b1 */
	ret = set_reg_iomap_bit(PCIE_CTRL_RST_REG, GET_PARA(4));
	mdelay(PCIE_DELAY_10);
	if (ret != HW_RET_SUCCESS)
		return ret;

	/* 5117L set PCIE swing specially */
	if (pcie_board_cfg->chan_attr[GET_PARA(1)].pcie_voltage_swing !=
		PCIE_INVALID_INT32) {
		/* PCIe controller 7 [ 13]:DBI CS enable */
		ret = write_reg_iomap_value(
			DBI_BASE_ADDR + DBI_SPACE_SIZE + 0x1c + GET_PARA(5), 0x2202800
		);
		if (ret != HW_RET_SUCCESS)
			return ret;

		/* 0x101600a0 #[9 : 7]:phy_tx_margin: set swing */
		ret = read_reg_iomap_value(DBI_BASE_ADDR + 0xa0 + GET_PARA(5), value);
		if (ret != HW_RET_SUCCESS)
			return ret;

		/* clear [9 : 7]bit */
		*value &= 0xFC7F;
		/* write to [9 : 7]bit */
		*value |= ((pcie_board_cfg->chan_attr[GET_PARA(1)].pcie_voltage_swing) << 7);
		ret = write_reg_iomap_value(DBI_BASE_ADDR + 0xa0 + GET_PARA(5), *value);
		if (ret != HW_RET_SUCCESS)
			return ret;

		mdelay(PCIE_DELAY_10);
	}

	/* de-reset pcie0 phy, 0x1488002c[12] = 1'b1 */
	ret |= set_reg_iomap_bit(PCIE_CTRL_RST_REG, GET_PARA(6));
	mdelay(PCIE_DELAY_10);
	/* de-reset pcie0 controller, 0x1488002c[18] = 1'b1 */
	ret |= set_reg_iomap_bit(PCIE_CTRL_RST_REG, GET_PARA(7));
	mdelay(PCIE_DELAY_10);

	return ret;
}

static int32_t pcie_undo_reset_5117l(struct pcie_board_ini_attr *pcie_board_cfg, bool is_open)
{
	int32_t ret = 0;

	if (!is_open)
		return 0;

	pcie_unreset_cel_chip(pcie_board_cfg);
	/* pcie0 cfg 2.4G */
	ret = DE_RESET_PCIE(0, 5117l_pcie, pcie_board_cfg, 0);
	if (ret != HW_RET_SUCCESS)
		return ret;

	/* pcie1 cfg 2.4G */
	ret = DE_RESET_PCIE(1, 5117l_pcie, pcie_board_cfg, 1);
	if (ret != HW_RET_SUCCESS)
		return ret;

	pcie_undo_reset_hi1152_chip(pcie_board_cfg);
	pcie_undo_reset_mxl_chip(pcie_board_cfg);

	return ret;
}

static int32_t undo_reset_5118v2_pcie(struct pcie_board_ini_attr *pcie_board_cfg, uint32_t index)
{
	int32_t ret;

	void *__iomem pcie_misc_base = NULL;
	const static int pcie_para_list[][2] = {
		/* paras for 5118v2 pcie0 and pcie1 */
		{PCIE_INDEX_0,       PCIE_INDEX_1},
		{PCIE0_REF_CLK_MASK, PCIE1_REF_CLK_MASK},
		{PCIE_BIT_13,        PCIE_BIT_14},
		{PCIE_BIT_18,        PCIE_BIT_22},
		{PCIE_BIT_6,         PCIE_BIT_7},
		{0,                  PCIE1_BASE_REG_OFFSET},
		{PCIE_BIT_8,         PCIE_BIT_9}
	};

	if (index >= ARRAY_SIZE(pcie_para_list[0]))
		return -EINVAL;

	pcie_get_misc_base_virt(GET_PARA(0), &pcie_misc_base);
	/* de-reset PICE0, wifi0 reset gpio */
	ret = set_gpio_dir_output(pcie_board_cfg->chan_attr[GET_PARA(0)].pcie_reset_gpio);

	ret |= set_gpio_dir_output(pcie_board_cfg->chan_attr[GET_PARA(0)].wifi_reset_gpio);
	ret |= set_gpio_output_value(
		pcie_board_cfg->chan_attr[GET_PARA(0)].pcie_reset_gpio, GPIO_IO_HIGH
	);
	ret |= set_gpio_output_value(
		pcie_board_cfg->chan_attr[GET_PARA(0)].wifi_reset_gpio, GPIO_IO_HIGH
	);
	mdelay(PCIE_DELAY_20);
	if (ret != HW_RET_SUCCESS)
		return ret;

	/* 0x14880040[2:0] = 0, wifi0_clk_ctrl = 0 */
	ret = clear_reg_iomap_mask(PCIE_REF_CLK_EN_REG, GET_PARA(1));
	/* open pcie0 clock 0x14880020[13] = 1 */
	ret |= set_reg_iomap_bit(PCIE_CLK_EN_REG2, GET_PARA(2));
	/* de-reset pcie0 phy and controller 0x1488002c[18] = 1 */
	ret |= set_reg_iomap_bit(PCIE_CTRL_RST_REG, GET_PARA(3));
	/* de-reset pcie0 apb interface 0x14880034[6] = 1 */
	ret |= set_reg_iomap_bit(PCIE_APB_RST_REG, GET_PARA(4));
	udelay(PCIE_DELAY_20);
	if (ret != HW_RET_SUCCESS)
		return ret;

	/* reset pcie0 pcs 0x1016103c[1] = 0 */
	clear_reg_bit(pcie_misc_base + PCIE_PCS_RST_OFFSET + GET_PARA(5), PCIE_BIT_1);
	udelay(PCIE_DELAY_20);
	/* reset pcie0 controller 0x1016103c[31] = 0 */
	clear_reg_bit(pcie_misc_base + PCIE_PCS_RST_OFFSET + GET_PARA(5), PCIE_BIT_31);
	udelay(PCIE_DELAY_20);
	/* de-reset pcie0 phy 0x14880034[8] = 1 */
	ret = set_reg_iomap_bit(PCIE_APB_RST_REG, GET_PARA(6));
	mdelay(PCIE_DELAY_20);
	/* de-reset pcie0 pcs 0x1016103c[1] = 1 */
	set_reg_bit(pcie_misc_base + PCIE_PCS_RST_OFFSET, GET_PARA(5));
	udelay(PCIE_DELAY_300);
	/* de-reset pcie0 controller 0x1016103c[31] = 1 */
	set_reg_bit(pcie_misc_base + PCIE_PCS_RST_OFFSET, GET_PARA(5));
	udelay(PCIE_DELAY_100);

	return ret;
}

static int32_t pcie_undo_reset_5118v2(struct pcie_board_ini_attr *pcie_board_cfg, bool is_open)
{
	int32_t ret;
	uint32_t val;

	if (!is_open)
		return 0;

	/* pcie module clk cfg */
	/* 0x14880084[8] = 1, config DL2DSH clock source as PLL FOUT2 */
	ret = set_reg_iomap_bit(PCIE_USR_DF_5118V2_REG, PCIE_BIT_8);
	/* 0x14880084[12] = 0, config SL2DL PD */
	ret = clear_reg_iomap_bit(PCIE_USR_DF_5118V2_REG, PCIE_BIT_12);
	/* 0x14880174[10:8] = 0x3, config SL2DL DRV */
	ret |= read_reg_iomap_value(PCIE_RCD_CTRL1_5118V2_REG, &val);
	val = PCIE__RCD_SL2DL_DRV_CFG(val);
	ret |= write_reg_iomap_value(PCIE_RCD_CTRL1_5118V2_REG, val);
	if (ret != HW_RET_SUCCESS)
		return ret;

	pcie_undo_reset_hi1152_chip(pcie_board_cfg);
	pcie_undo_reset_mxl_chip(pcie_board_cfg);
	pcie_unreset_cel_chip(pcie_board_cfg);

	/* if both pcie in using, de-reset pcie1 first */
	ret = DE_RESET_PCIE(1, 5118v2_pcie, pcie_board_cfg, 1);
	if (ret != HW_RET_SUCCESS)
		return ret;

	ret = DE_RESET_PCIE(0, 5118v2_pcie, pcie_board_cfg, 0);
	return ret;
}

static int32_t undo_reset_5610t_pcie0(struct pcie_board_ini_attr *pcie_board_cfg)
{
	int32_t ret;

	/* de-reset pcie0 */
	ret = set_gpio_dir_output(pcie_board_cfg->chan_attr[PCIE_INDEX_0].pcie_reset_gpio);
	ret |= set_gpio_dir_output(pcie_board_cfg->chan_attr[PCIE_INDEX_0].wifi_reset_gpio);
	ret |= set_gpio_output_value(
		pcie_board_cfg->chan_attr[PCIE_INDEX_0].pcie_reset_gpio, GPIO_IO_HIGH
	);
	if (ret != HW_RET_SUCCESS)
		return ret;

	mdelay(PCIE_DELAY_50);

	/* disable PCIE 0 CLK */
	ret = clear_reg_iomap_bit(PCIE_IOMUX_GROP_5610T_REG, PCIE_BIT_0);
	if (ret != HW_RET_SUCCESS)
		return ret;

	mdelay(PCIE_DELAY_10);

	/* de-reset wifi0 */
	ret = set_gpio_output_value(
		pcie_board_cfg->chan_attr[PCIE_INDEX_0].wifi_reset_gpio, GPIO_IO_HIGH
	);
	if (ret != HW_RET_SUCCESS)
		return ret;

	mdelay(PCIE_DELAY_50);

	ret = write_reg_iomap_value(PCIE0_CTRL_CFG_5610T_REG, PCIE_CTRL_CFG_5610T_VALUE);
	mdelay(PCIE_DELAY_10);
	/* 23bit reset pcie0 controller */
	ret |= clear_reg_iomap_bit(PCIE_CTRL_RST_5610T_REG, PCIE_BIT_23);
	mdelay(PCIE_DELAY_1000);
	/* 23bit de-reset pcie0 controller */
	ret |= set_reg_iomap_bit(PCIE_CTRL_RST_5610T_REG, PCIE_BIT_23);
	mdelay(PCIE_DELAY_10);

	pr_info("pcie0 undo reset fail ret=0x%x!\n", ret);
	return ret;
}

static int32_t undo_reset_5610t_pcie1(struct pcie_board_ini_attr *pcie_board_cfg)
{
	int32_t ret;

	/* de-reset pcie1 */
	ret = set_gpio_dir_output(pcie_board_cfg->chan_attr[PCIE_INDEX_1].pcie_reset_gpio);
	ret |= set_gpio_dir_output(pcie_board_cfg->chan_attr[PCIE_INDEX_1].wifi_reset_gpio);
	ret |= set_gpio_output_value(pcie_board_cfg->chan_attr[PCIE_INDEX_1].pcie_reset_gpio,
		GPIO_IO_HIGH);
	if (ret != HW_RET_SUCCESS)
		return ret;

	mdelay(PCIE_DELAY_50);

	/* enable module clk */
	ret = set_reg_iomap_mask(PCIE_CLK_EN_REG2, PCIE_CTRL_RST_5610T_VALUE);
	if (ret != HW_RET_SUCCESS)
		return ret;

	mdelay(PCIE_DELAY_10);

	/* de-reset wifi1 */
	ret |= set_gpio_output_value(
		pcie_board_cfg->chan_attr[PCIE_INDEX_1].wifi_reset_gpio, GPIO_IO_HIGH
	);
	if (ret != HW_RET_SUCCESS)
		return ret;

	mdelay(PCIE_DELAY_50);

	ret = write_reg_iomap_value(PCIE1_CTRL_CFG_5610T_REG, PCIE_CTRL_CFG_5610T_VALUE);
	mdelay(PCIE_DELAY_10);
	/* 24bit reset pcie0 controller */
	ret |= clear_reg_iomap_bit(PCIE_CTRL_RST_5610T_REG, PCIE_BIT_24);
	mdelay(PCIE_DELAY_1000);
	/* 24bit de-reset pcie0 controller */
	ret |= set_reg_iomap_bit(PCIE_CTRL_RST_5610T_REG, PCIE_BIT_24);
	mdelay(PCIE_DELAY_10);

	pr_info("pcie1 undo reset fail ret=0x%x!\n", ret);
	return ret;
}

static int32_t pcie_undo_reset_5610t(struct pcie_board_ini_attr *pcie_board_cfg, bool is_open)
{
	int32_t ret;

	if (!is_open)
		return 0;

	/* enable wifi ref CLK */
	ret = write_reg_iomap_value(PCIE_IOMUX_GROP_5610T_REG, 0);

	ret |= clear_reg_iomap_bit(PCIE_REF_CLK_EN_REG, PCIE_BIT_1);
	ret |= clear_reg_iomap_bit(PCIE_REF_CLK_EN_REG, PCIE_BIT_2);
	/* disable PCIE 0 CLK */
	ret |= set_reg_iomap_bit(PCIE_IOMUX_GROP_5610T_REG, PCIE_BIT_0);
	if (ret != HW_RET_SUCCESS)
		return ret;

	/* if both pcie in using, de-reset pcie1 first */
	ret = DE_RESET_PCIE(1, 5610t_pcie1, pcie_board_cfg);
	if (ret != HW_RET_SUCCESS)
		return ret;

	/* de-reset pcie0 */
	ret = DE_RESET_PCIE(0, 5610t_pcie0, pcie_board_cfg);
	return 0;
}

static int32_t init_5182h_pcie_and_wifi_clk(uint32_t chn_sel)
{
	uint32_t pcie_phy_clk_mask;
	uint32_t pcie_clk_en;
	uint32_t pcie_pad_cfg_reg;
	int32_t ret;

	pcie_phy_clk_mask = PCIE0_REF_CLK_EN_MASK;
	pcie_clk_en = PCIE_BIT_12;
	pcie_pad_cfg_reg = PCIE0_PAD_CFG_5182X_REG;
	if (chn_sel == PCIE1_MODE_SEL) {
		pcie_phy_clk_mask = PCIE1_5182H_REF_CLK_MASK;
		pcie_clk_en = PCIE_BIT_13;
		pcie_pad_cfg_reg = PCIE1_PAD_CFG_5182X_REG;
	}

	/* enable pcie and wifi clk signal */
	/* enable pcie phy and wifi ref clk control signal */
	ret = clear_reg_iomap_mask(PCIE_REF_CLK_EN_REG, pcie_phy_clk_mask);
	/* enable pcie clk*/
	ret |= set_reg_iomap_bit(PCIE_CLK_EN_REG2, pcie_clk_en);
	/* set enable and drv ability for of 100Mhz WIFI output differential clk */
	ret |= set_reg_iomap_mask(pcie_pad_cfg_reg, PCIE_PAD_CFG_5182X_VALUE);
	return ret;
}

static int32_t init_5182h_phy_and_pcs(struct pcie_board_ini_attr *pcie_board_cfg, uint32_t chn_sel)
{
	uint32_t apb_en;
	uint32_t pcs_en;
	uint32_t phy_en;
	uint32_t ctrl_en;
	int32_t ret;

	apb_en = PCIE_BIT_12;
	pcs_en = PCIE_BIT_13;
	phy_en = PCIE_BIT_14;
	ctrl_en = PCIE_BIT_15;
	if (chn_sel == PCIE1_MODE_SEL) {
		apb_en = PCIE_BIT_16;
		pcs_en = PCIE_BIT_17;
		phy_en = PCIE_BIT_18;
		ctrl_en = PCIE_BIT_19;
	}

	/* de-reset pcie apb, phy, pcsand ctl module in required order */
	/* de-reset pcie0 apb, 0x14880034 */
	ret = set_reg_iomap_bit(PCIE_APB_RST_REG, apb_en);

	mdelay(PCIE_DELAY_10);
	if (chn_sel == PCIE0_MODE_SEL) {
		/* set  pcie0 swing based on cfg file */
		ret |= set_pcie0_votage_swing(pcie_board_cfg);
	} else {
		/* set  pcie1 swing based on cfg file */
		ret |= set_pcie1_votage_swing(pcie_board_cfg);
	}
	ret |= set_reg_iomap_bit(PCIE_APB_RST_REG, phy_en);  /* de-reset pcie0 phy, 0x14880034 */
	mdelay(PCIE_DELAY_10);
	ret |= set_reg_iomap_bit(PCIE_APB_RST_REG, pcs_en);  /* de-reset pcie0 pcs, 0x14880034 */
	mdelay(PCIE_DELAY_10);
	/* de-reset pcie0 controller, 0x14880034 */
	ret |= set_reg_iomap_bit(PCIE_APB_RST_REG, ctrl_en);
	mdelay(PCIE_DELAY_10);
	return ret;
}

static int32_t init_5182t_pcie_and_wifi_clk(uint32_t chn_sel)
{
	uint32_t ret;
	uint32_t pcie_clk_mask = PCIE0_CLK_EN_MASK_5182T;

	/* 5182T only enable pcie clk PCIE_CLK_EN_REG2 */
	if (chn_sel == PCIE1_MODE_SEL)
		pcie_clk_mask = PCIE1_CLK_EN_MASK_5182T;
	else if (chn_sel == PCIE2_MODE_SEL)
		pcie_clk_mask = PCIE2_CLK_EN_MASK_5182T;

	/* open pcie and wifi clk signal */
	ret = set_reg_iomap_mask(PCIE_CLK_EN_REG2, pcie_clk_mask); /* PCIE clk enable */
	return ret;
}

static int32_t init_5182t_phy_and_pcs(struct pcie_board_ini_attr *pcie_board_cfg, uint32_t chn_sel)
{
	uint32_t pcie_apb_reg_addr;
	uint32_t apb_en;
	uint32_t phy_en;
	uint32_t sds2pcs_rx0;
	uint32_t sds2pcs_rx1;
	uint32_t sds2pcs_tx;
	uint32_t slv_axi_en;
	uint32_t mstr_axi_en;
	uint32_t pcs_local;
	int32_t ret;

	pcie_apb_reg_addr = PCIE_APB_RST_REG_5182T;
	pcs_local = PCIE_BIT_7;
	phy_en = PCIE_BIT_8;
	mstr_axi_en = PCIE_BIT_9;
	slv_axi_en = PCIE_BIT_10;
	apb_en = PCIE_BIT_11;
	sds2pcs_tx = PCIE_BIT_12;
	sds2pcs_rx1 = PCIE_BIT_13;
	sds2pcs_rx0 = PCIE_BIT_14;
	if (chn_sel == PCIE1_MODE_SEL) {
		phy_en = PCIE_BIT_0;
		pcs_local = PCIE_BIT_1;
		mstr_axi_en = PCIE_BIT_2;
		apb_en = PCIE_BIT_3;
		slv_axi_en = PCIE_BIT_4;
		sds2pcs_tx = PCIE_BIT_5;
		sds2pcs_rx1 = PCIE_BIT_6;
	} else if (chn_sel == PCIE2_MODE_SEL) {
		pcie_apb_reg_addr = PCIE_APB_RST_REG;
		mstr_axi_en = PCIE_BIT_10;
		slv_axi_en = PCIE_BIT_11;
		apb_en = PCIE_BIT_12;
		phy_en = PCIE_BIT_14;
	}

	/* de-reset pcie apb, phy, pcsand ctl module in required order */
	ret = set_reg_iomap_bit(pcie_apb_reg_addr, apb_en); /* apb de-reset */
	mdelay(PCIE_DELAY_100);
	if (chn_sel == PCIE0_MODE_SEL) {
		/* set pcie0 swing based on cfg file */
		ret |= set_pcie0_votage_swing(pcie_board_cfg);
	} else if (chn_sel == PCIE1_MODE_SEL) {
		/* set pcie1 swing based on cfg file */
		ret |= set_pcie1_votage_swing(pcie_board_cfg);
	} else {
		/* set pcie2 swing based on cfg file */
		ret |= set_pcie2_votage_swing(pcie_board_cfg);
	}

	ret |= set_reg_iomap_bit(pcie_apb_reg_addr, phy_en);	  /* phy de-reset */
	mdelay(PCIE_DELAY_100);

	if (chn_sel == PCIE0_MODE_SEL) {
		ret |= set_reg_iomap_bit(pcie_apb_reg_addr, sds2pcs_rx0);  /* sds2pcs_rx0 */
		mdelay(PCIE_DELAY_10);
	}

	if (chn_sel != PCIE2_MODE_SEL) {
		ret |= set_reg_iomap_bit(pcie_apb_reg_addr, sds2pcs_rx1); /* sds2pcs_rx1 */
		mdelay(PCIE_DELAY_10);
		ret |= set_reg_iomap_bit(pcie_apb_reg_addr, sds2pcs_tx);  /* sds2pcs_tx */
		mdelay(PCIE_DELAY_10);
	}

	ret |= set_reg_iomap_bit(pcie_apb_reg_addr, slv_axi_en);  /* slv_axi de-reset */
	mdelay(PCIE_DELAY_10);
	ret |= set_reg_iomap_bit(pcie_apb_reg_addr, mstr_axi_en); /* mstr_axi de-reset */
	mdelay(PCIE_DELAY_10);

	if (chn_sel != PCIE2_MODE_SEL) {
		ret |= set_reg_iomap_bit(pcie_apb_reg_addr, pcs_local); /* pcs_local */
		mdelay(PCIE_DELAY_10);
	}

	return ret;
}

static int32_t init_5182x_pcie_and_wifi_clk(uint32_t chn_sel)
{
	uint32_t chip_id;
	int32_t ret = -ENXIO;

	chip_id = pcie_get_chip_id();
	if (chip_id == HAL_CHIP_ID_5182T)
		ret = init_5182t_pcie_and_wifi_clk(chn_sel);
	else if ((chip_id == HAL_CHIP_ID_5182HV5) || (chip_id == HW_CHIP_ID_5182H_E))
		ret = init_5182h_pcie_and_wifi_clk(chn_sel);

	return ret;
}

static int32_t init_5182x_phy_and_pcs(struct pcie_board_ini_attr *pcie_board_cfg, uint32_t chn_sel)
{
	uint32_t chip_id;
	int32_t ret = -ENXIO;

	chip_id = pcie_get_chip_id();
	if (chip_id == HAL_CHIP_ID_5182T)
		ret = init_5182t_phy_and_pcs(pcie_board_cfg, chn_sel);
	else if ((chip_id == HAL_CHIP_ID_5182HV5) || (chip_id == HW_CHIP_ID_5182H_E))
		ret = init_5182h_phy_and_pcs(pcie_board_cfg, chn_sel);

	return ret;
}

static int32_t undo_reset_5182x_pcie(struct pcie_board_ini_attr *pcie_board_cfg, uint32_t chn_index)
{
	int32_t ret;
	uint32_t pcie_gpio_ability;
	uint32_t pcie_reset_gpio;
	uint32_t wifi_reset_gpio;
	uint32_t qca_wifi_reset_gpio;
	uint32_t chn_sel;

	pcie_gpio_ability = PCIE_GPIO_MAX_ABILITY;
	pcie_reset_gpio = pcie_board_cfg->chan_attr[chn_index].pcie_reset_gpio;
	wifi_reset_gpio = pcie_board_cfg->chan_attr[chn_index].wifi_reset_gpio;
	/* 0. reset pcie and wifi */
	/* set gpio mode */
	ret = set_gpio_dir_output(pcie_reset_gpio);

	ret |= set_gpio_dir_output(wifi_reset_gpio);
	/* set pcie and wifi reset gpio drv ability max, if cfg info exists, set as cfg */
	if (pcie_board_cfg->chan_attr[chn_index].pcie_drv_ability < PCIE_GPIO_MAX_ABILITY)
		pcie_gpio_ability = pcie_board_cfg->chan_attr[chn_index].pcie_drv_ability;

	ret |= set_gpio_drv_ability(pcie_reset_gpio, pcie_gpio_ability);
	ret |= set_gpio_drv_ability(wifi_reset_gpio, pcie_gpio_ability);
	/* reset pcie wifi */
	ret |= set_gpio_output_value(pcie_reset_gpio, GPIO_IO_LOW);
	ret |= set_gpio_output_value(wifi_reset_gpio, GPIO_IO_LOW);
	if (ret != HW_RET_SUCCESS)
		return ret;

	/* qualcomm wifi reset gpio reset, after 640ms de-reset, more 60ms, de-reset pcie reset */
	qca_wifi_reset_gpio = pcie_board_cfg->qca_wifi_attr[chn_index].qca_wifi_reset_gpio;

	if (pcie_is_wifi_qca_chip(chn_index) && (qca_wifi_reset_gpio != PCIE_INVALID_INT8)) {
		pcie_set_qca_wifi_reset(qca_wifi_reset_gpio);
		pr_info("qca_wifi%u_reset_gpio = %u\n", chn_index, qca_wifi_reset_gpio);
		mdelay(PCIE_DELAY_10);
	}

	/* 1. oprn pcie and wifi clk signal */
	chn_sel = (chn_index == PCIE_INDEX_0) ? PCIE0_MODE_SEL : PCIE1_MODE_SEL;
	if (chn_index == PCIE_INDEX_2)
		chn_sel = PCIE2_MODE_SEL;

	ret = init_5182x_pcie_and_wifi_clk(chn_sel);
	if (ret != HW_RET_SUCCESS)
		return ret;

	mdelay(PCIE_DELAY_10);

	/* 2. de-reset pcie and wifi */
	if (pcie_is_extlsw_chip(chn_index)) {
		ret = set_gpio_output_value(wifi_reset_gpio, GPIO_IO_HIGH);
		/* extlsw de-reset, ready after 150ms. now de-reset other PCIE */
		mdelay(PCIE_DELAY_200);
		ret |= set_gpio_output_value(pcie_reset_gpio, GPIO_IO_HIGH);
	} else {
		ret = set_gpio_output_value(pcie_reset_gpio, GPIO_IO_HIGH);
		ret |= set_gpio_output_value(wifi_reset_gpio, GPIO_IO_HIGH);
	}
	if (ret != HW_RET_SUCCESS)
		return ret;

	mdelay(PCIE_DELAY_10);

	/* 3. de-reset pcie apb, phy, pcs and ctl module in required order */
	ret = init_5182x_phy_and_pcs(pcie_board_cfg, chn_sel);
	return ret;
}

int32_t pcie_undo_reset_5182x(struct pcie_board_ini_attr *pcie_board_cfg, bool is_open)
{
	int32_t ret = 0;

	if (!is_open)
		return 0;

	pcie_proc_qca_wifi_unreset(pcie_board_cfg);
	pcie_unreset_cel_chip(pcie_board_cfg);
	pcie_preprocess_dy1153_chip(pcie_board_cfg);

	/* pcie0 cfg */
	ret = DE_RESET_PCIE(0, 5182x_pcie, pcie_board_cfg, PCIE_INDEX_0);
	if (ret != HW_RET_SUCCESS)
		return ret;

	/* pcie1 cfg */
	ret = DE_RESET_PCIE(1, 5182x_pcie, pcie_board_cfg, PCIE_INDEX_1);
	if (ret != HW_RET_SUCCESS)
		return ret;

	/* pcie2 cfg */
	ret = DE_RESET_PCIE(2, 5182x_pcie, pcie_board_cfg, PCIE_INDEX_2);
	if (ret != HW_RET_SUCCESS)
		return ret;

	pcie_undo_reset_hi1152_chip(pcie_board_cfg);
	pcie_undo_reset_dy1153_chip(pcie_board_cfg);
	pcie_undo_reset_mxl_chip(pcie_board_cfg);

	/* ACP set enable */
	pcie_config_channel_acp(pcie_board_cfg);

	return ret;
}
#endif

int32_t pcie_undo_reset(bool is_open)
{
	uint32_t chip_index;
	uint32_t chip_index_max;
	uint32_t chip_id;
	int32_t ret;
	struct pcie_board_ini_attr *pcie_board_cfg;
	struct pcie_undo_reset_select pcie_unreset[] = {
		{ HW_CHIP_ID_5115T_E,   pcie_undo_reset_5115   },
		{ HW_CHIP_ID_5115H_E,   pcie_undo_reset_5115   },
		{ HW_CHIP_ID_5116H_E,   pcie_undo_reset_5116h  },
		{ HW_CHIP_ID_5116T_E,   pcie_undo_reset_5116t  },
		{ HW_CHIP_ID_5118_E,    pcie_undo_reset_5118   },
		{ HW_CHIP_ID_5117H_E,   pcie_undo_reset_5117h  },
		{ HW_CHIP_ID_5117P_E,   pcie_undo_reset_5117p  },
		{ HW_CHIP_ID_5117V_E,   pcie_undo_reset_5117v  },
		{ HW_CHIP_ID_5118V2_E,  pcie_undo_reset_5118v2 },
		{ HW_CHIP_ID_5610T_E,   pcie_undo_reset_5610t  },
		{ HW_CHIP_ID_5117L_E,   pcie_undo_reset_5117l  },
		{ HW_CHIP_ID_5182H_E,   pcie_undo_reset_5182x  },
		{ HAL_CHIP_ID_5117PV5,  pcie_undo_reset_5117p  },
		{ HAL_CHIP_ID_5182HV5,  pcie_undo_reset_5182x  },
		{ HAL_CHIP_ID_5182T,    pcie_undo_reset_5182x  },
		{ HW_CHIP_ID_5116TV5_E, pcie_undo_reset_5116t  },
		{ HAL_CHIP_ID_1156H,    pcie_undo_reset_1156   },
		{ HAL_CHIP_ID_1155H,    pcie_undo_reset_1156   },
		{ HAL_CHIP_ID_1156E,    pcie_undo_reset_1156   },
		{ HAL_CHIP_ID_2952H,    pcie_undo_reset_1156   },
		{ HW_CHIP_ID_MPW_E,     NULL                   },
	};

	chip_id = pcie_get_chip_id();
	pcie_get_board_attr(&pcie_board_cfg);
	chip_index_max = ARRAY_SIZE(pcie_unreset);
	for (chip_index = 0; chip_index < chip_index_max; chip_index++) {
		if ((chip_id == pcie_unreset[chip_index].chip_id) &&
		    (pcie_unreset[chip_index].pf_pcie_undo_reset != NULL)) {
			ret = pcie_unreset[chip_index].pf_pcie_undo_reset(pcie_board_cfg, is_open);
			break;
		}
	}

	if (!is_open)
		return ret;

	if (chip_index_max == chip_index) {
		pr_info("not found chip_type=%d pcie de-reset hook\n", chip_id);
		return -ECHILD;
	}

	if (pcie_board_cfg->pcie_channel_select & PCIE0_MODE_SEL)
		hi_pcie_post_config(0);

	if (pcie_board_cfg->pcie_channel_select & PCIE1_MODE_SEL)
		hi_pcie_post_config(1);

	return ret;
}
